import { Page } from '@/models';
import { useAsync } from '@ahooksjs/use-request';
import { BaseOptions, BaseResult } from '@ahooksjs/use-request/lib/types';
import { useUpdateEffect } from 'ahooks';
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { ResponseResult, Result } from './type';

export type LoadMoreService<
  R extends Page<Record<string, unknown>>,
  P extends Record<string, unknown> = Record<string, unknown>
> = (
  params: P & {
    pageSize: number;
    pageNum: number;
  }
) => Result<R>;
export interface LoadMoreOptions<R> extends BaseOptions<R, any> {
  isNoMore?: (r: R) => boolean;
}
export interface LoadMoreResult<R, P extends any[] = any> extends BaseResult<R, P> {
  noMore?: boolean;
  loadMore: () => void;
  reload: () => void;
  loadingMore: boolean;
}
/**
 *
 * @param service
 * @param options
 * @returns
 */
function useLoadMore<
  R extends Page<Record<string, any>>,
  P extends Record<string, unknown> = Record<string, unknown>
>(service: LoadMoreService<R, P>, options: LoadMoreOptions<R>): LoadMoreResult<R> {
  const { refreshDeps = [], isNoMore, fetchKey, defaultParams = [], ...restOptions } = options;

  const [loadingMore, setLoadingMore] = useState(false);
  useEffect(() => {
    if (fetchKey) {
      console.warn("useRequest loadMore mode don't need fetchKey!");
    }
  }, []);

  const page = useRef(1);
  const promiseService = (...args: any[]) =>
    new Promise((resolve, reject) => {
      const [arg1] = args;
      service({ pageNum: page.current, pageSize: 20, ...arg1 }).then(
        (data: ResponseResult<unknown>) => {
          if (data.ok) {
            resolve(data.data);
          } else {
            reject(data.err);
          }
        }
      );
    });
  const result: any = useAsync(promiseService, {
    ...(restOptions as any),
    defaultParams,
    fetchKey: () => {
      return page.current;
    },
    onSuccess: (...params) => {
      setLoadingMore(false);
      if (options.onSuccess) {
        options.onSuccess(...params);
      }
    }
  });

  const { data, run, reset, loading, fetches } = result;
  const reload = useCallback(() => {
    page.current = 1;
    reset();
    run(...defaultParams);
  }, [run, reset, defaultParams]);

  const reloadRef = useRef(reload);
  reloadRef.current = reload;
  /* loadMore 场景下，如果 refreshDeps 变化，重置到第一页 */
  useUpdateEffect(() => {
    /* 只有自动执行的场景， refreshDeps 才有效 */
    if (!options.manual) {
      reloadRef.current();
    }
  }, [...refreshDeps]);

  const dataGroup = useMemo(() => {
    let listGroup: any[] = [];
    // 在 loadMore 时，不希望清空上一次的 data。需要把最后一个 非 loading 的请求 data，放回去。
    let lastNoLoadingData: R = data;
    Object.values(fetches).forEach((h: any) => {
      if (h.data?.list) {
        listGroup = listGroup.concat(h.data?.list);
      }
      if (!h.loading) {
        lastNoLoadingData = h.data;
      }
    });
    return {
      ...lastNoLoadingData,
      list: listGroup
    };
  }, [fetches, data]);
  const noMore = isNoMore ? !loading && !loadingMore && isNoMore(dataGroup) : false;

  const loadMore = useCallback(() => {
    if (noMore) {
      return;
    }
    page.current += 1;
    setLoadingMore(true);
    run(...defaultParams);
  }, [noMore, run, defaultParams]);

  return {
    ...result,
    data: dataGroup,
    reload,
    loading: loading && dataGroup.list.length === 0,
    loadMore,
    loadingMore,
    noMore
  };
}

export default useLoadMore;
